home *** CD-ROM | disk | FTP | other *** search
/ PC Pro 2005 June (DVD) / DPPRO0605DVD.iso / Install / program files / Borland / BDS / 3.0 / Demos / Delphi.Net / CLR / ProcessViewer / ProcessCheckerClass.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  2004-10-22  |  8.3 KB  |  269 lines

  1. unit ProcessCheckerClass;
  2. {*******************************************************************************
  3.   ProcessChecker Demo
  4.   Written by David Clegg, davidclegg@optusnet.com.au.
  5.  
  6.   This unit contains the TProcessChecker class, which is responsible for
  7.   monitoring, stopping and restarting processes.
  8. *******************************************************************************}
  9. interface
  10.  
  11. uses
  12.   ProcessCheckerSettings, System.Windows.Forms, System.Diagnostics,
  13.   ProcessClasses;
  14.  
  15. type
  16.   TProcessCheckerEvent = procedure (Sender: TObject; const EventMessage: string) of object;
  17.   TProcessArray = Array of Process;
  18.  
  19.     /// <summary>
  20.     /// Class to handle the Process monitoring.
  21.     /// </summary>
  22.   TProcessChecker = class
  23.   strict private
  24.     FOnEvent: TProcessCheckerEvent;
  25.     FSettings: TProcessCheckerSettings;
  26.     FSuspended: boolean;
  27.     FTimer: Timer;
  28.     procedure InitTimer;
  29.     procedure InitSettings;
  30.     procedure SetTimerInterval;
  31.     procedure CheckProcesses;
  32.     procedure TimerTick(Sender: TObject; Args: EventArgs);
  33.     procedure SettingsUpdated(Sender: TObject; Args: EventArgs);
  34.     function CheckProcess(pProcessPath: string): TProcessArray;
  35.     procedure RestartProcess(pProcess: TWatchedProcess);
  36.     procedure NotifyEvent(const pEventDetails: string);
  37.     procedure StopProcess(pProcess: Process);
  38.     procedure StopDependantProcesses(pProcess: TWatchedProcess);
  39.   public
  40.     property OnEvent: TProcessCheckerEvent read FOnEvent write FOnEvent;
  41.     property Settings: TProcessCheckerSettings read FSettings write FSettings;
  42.     property Suspended: boolean read FSuspended write FSuspended;
  43.     constructor Create(const pSettings: TProcessCheckerSettings);
  44.   end;
  45.  
  46. implementation
  47.  
  48. uses
  49.   System.IO, System.Threading, SysUtils;
  50.  
  51. constructor TProcessChecker.Create(const pSettings: TProcessCheckerSettings);
  52. begin
  53.   inherited Create;
  54.   FSettings := pSettings;
  55.   InitTimer;
  56.   InitSettings;
  57. end;
  58.  
  59. /// <summary>
  60. /// Create the timer, and attach the Tick event.
  61. /// </summary>
  62. procedure TProcessChecker.InitTimer;
  63. begin
  64.   FTimer := System.Windows.Forms.Timer.Create;
  65.   Include(FTimer.Tick, TimerTick);
  66.   SetTimerInterval;
  67. end;
  68.  
  69. /// <summary>
  70. /// Sets the interval for the timer used to trigger the process checking
  71. /// </summary>
  72. procedure TProcessChecker.SetTimerInterval;
  73. var
  74.   lInterval: integer;
  75. begin
  76.   //CheckFrequency is stored in seconds, but we need to convert it
  77.   //to milliseconds for the timer.
  78.   lInterval := FSettings.CheckFrequency * 1000;
  79.  
  80.   //The Timer class will throw an exception if we attempt to assign an
  81.   //interval with a zero value
  82.   if (lInterval > 0) then
  83.   begin
  84.     FTimer.Interval := lInterval;
  85.     FTimer.Enabled := FSettings.Enabled;
  86.   end
  87.   else
  88.   begin
  89.     //Ensure timer is disabled
  90.     FTimer.Enabled := false;
  91.     if FSettings.Enabled then
  92.     begin
  93.       FSettings.Enabled := false;
  94.       FSettings.Save;
  95.     end;
  96.   end;
  97. end;
  98.  
  99. procedure TProcessChecker.TimerTick(Sender: TObject; Args: EventArgs);
  100. begin
  101.   CheckProcesses;
  102. end;
  103.  
  104. /// <summary>
  105. /// Create the ProcessCheckerSettings instance, and attach the event
  106. /// handlers to notify when the instance is loaded or saved.
  107. /// </summary>
  108. procedure TProcessChecker.InitSettings;
  109. begin
  110.   Include(FSettings.SettingsLoaded, SettingsUpdated);
  111.   Include(FSettings.SettingsSaved, SettingsUpdated);
  112.  
  113.   //As the event handlers are attached after the settings are
  114.   //initially loaded from disk, we need to fire the event manually.
  115.   SettingsUpdated(Self, nil);
  116. end;
  117.  
  118. /// <summary>
  119. /// Event handler called if the ProcessCheckerSettings instance is loaded
  120. /// or saved. As we are only interested in determining that the settings
  121. /// may have changed (and not what caused the change), we can share the
  122. /// event handler.
  123. /// </summary)
  124. procedure TProcessChecker.SettingsUpdated(Sender: TObject; Args: EventArgs);
  125. begin
  126.   SetTimerInterval;
  127. end;
  128.  
  129. /// <summary>
  130. /// Iterate through all monitored processes to check whether they are
  131. /// still running.
  132. /// </summary>
  133. procedure TProcessChecker.CheckProcesses;
  134. var
  135.   lProcesses: TProcessArray;
  136.   i: integer;
  137.   j: integer;
  138.   lWatchedProcess: TWatchedProcess;
  139.   lRunningProcess: Process;
  140. begin
  141.   if not FSuspended then
  142.     for i := 0 to FSettings.WatchedProcesses.Count -1 do
  143.     begin
  144.       lWatchedProcess := FSettings.WatchedProcesses[i] as TWatchedProcess;
  145.       lProcesses := CheckProcess(lWatchedProcess.Path);
  146.       if (Length(lProcesses) = 0) then
  147.       begin
  148.         //No instances of lWatchedProcess running, so re-start it
  149.         RestartProcess(lWatchedProcess);
  150.         if (FSettings.RestartOneProcess) then
  151.           //We only restart one process each time we check
  152.           //running processes. Any subsequent processes that have
  153.           //unexpectedly terminated will be caught next time.
  154.           break;
  155.       end
  156.       else
  157.         for j := 0 to Length(lProcesses) -1 do
  158.         begin
  159.           //At least one instance of lWatchedProcess running,
  160.           //so check that the instance(s) are still responding.
  161.           lRunningProcess := lProcesses[j];
  162.           if lWatchedProcess.CheckResponding then
  163.             if not (lRunningProcess.Responding) then
  164.             begin
  165.               //Process not responding, so re-start it.
  166.               NotifyEvent(Format('%s - not responding',
  167.                 [lRunningProcess.ProcessName]));
  168.               StopProcess(lRunningProcess);
  169.               RestartProcess(lWatchedProcess);
  170.               if (FSettings.RestartOneProcess) then
  171.                 //Only restarting one process per check.
  172.                 break;
  173.             end;
  174.         end;
  175.   end;
  176. end;
  177.  
  178. /// <summary>
  179. /// Check to see whether the specified process is still running.
  180. /// Returns an array of Process instances if the process has at least one
  181. /// running instance.
  182. /// </summary>
  183. function TProcessChecker.CheckProcess(pProcessPath: string): TProcessArray;
  184. var
  185.   lProcessName: string;
  186. begin
  187.   lProcessName := System.IO.Path.GetFileNameWithoutExtension(pProcessPath);
  188.   Result := Process.GetProcessesByName(lProcessName);
  189. end;
  190.  
  191. /// <summary>
  192. /// Restart a process.
  193. /// </summary>
  194. procedure TProcessChecker.RestartProcess(pProcess: TWatchedProcess);
  195. var
  196.   lStartProcess: Process;
  197. begin
  198.   StopDependantProcesses(pProcess);
  199.   lStartProcess := Process.Create;
  200.   lStartProcess.StartInfo.FileName := pProcess.Path;
  201.   lStartProcess.StartInfo.WorkingDirectory := Path.GetDirectoryName(pProcess.Path);
  202.   try
  203.     lStartProcess.Start();
  204.     NotifyEvent(Format('%s - Process restarted', [pProcess.Name]));
  205.   except on E: Exception do
  206.     NotifyEvent(Format('Error starting %s - %s',
  207.       [pProcess.Name, E.Message]));
  208.   end;
  209. end;
  210.  
  211. /// <summary>
  212. /// Iterate through, and terminate, all dependant processes.
  213. /// </summary>
  214. procedure TProcessChecker.StopDependantProcesses(pProcess: TWatchedProcess);
  215. var
  216.   lDependantProcesses: TProcessArray;
  217.   i: integer;
  218.   j: integer;
  219. begin
  220.   for i := 0 to pProcess.DependantProcesses.Count -1 do
  221.   begin
  222.     lDependantProcesses := CheckProcess(pProcess.DependantProcesses[i].Path);
  223.     for j := 0 to Length(lDependantProcesses) -1 do
  224.       StopProcess(lDependantProcesses[j]);
  225.   end;
  226. end;
  227.  
  228. /// <summary>
  229. /// Stop a process.
  230. /// </summary>
  231. procedure TProcessChecker.StopProcess(pProcess: Process);
  232. begin
  233.   //Attempt to stop the process 'nicely' by sending a Close message
  234.   //to the processes main window
  235.   pProcess.CloseMainWindow();
  236.   //Give the message a chance to be processed
  237.   Thread.Sleep(100);
  238.   if not pProcess.HasExited then
  239.   begin
  240.     //CloseMainWindow didn't work so attempt a more forceful
  241.     //shutdown. Process.Kill forces an immediate termination of the
  242.     //process.
  243.     pProcess.Kill;
  244.     Thread.Sleep(100);
  245.     if not pProcess.HasExited then
  246.       //Still running, but its time to admit defeat :-(
  247.       NotifyEvent(Format('%s - Process termination failed',
  248.         [pProcess.ProcessName]))
  249.     else
  250.       NotifyEvent(Format('%s - Process killed', [pProcess.ProcessName]));
  251.   end
  252.   else
  253.     NotifyEvent(Format('%s - Process stopped' , [pProcess.ProcessName]));
  254. end;
  255.  
  256. /// <summary>
  257. /// Send a Process Checker Event notification.
  258. /// </summary>
  259. procedure TProcessChecker.NotifyEvent(const pEventDetails: string);
  260. begin
  261.   if Assigned(FOnEvent) then
  262.     FOnEvent(Self, pEventDetails);
  263. end;
  264.  
  265. end.
  266.  
  267.  
  268.  
  269.